Tools-side support for creating and destroying netchannel2 interfaces.
authorKeir Fraser <keir.fraser@citrix.com>
Wed, 7 Oct 2009 06:47:50 +0000 (07:47 +0100)
committerKeir Fraser <keir.fraser@citrix.com>
Wed, 7 Oct 2009 06:47:50 +0000 (07:47 +0100)
Signed-off-by: Steven Smith <steven.smith@citrix.com>
tools/hotplug/Linux/Makefile
tools/hotplug/Linux/vif2 [new file with mode: 0644]
tools/hotplug/Linux/xen-backend.rules
tools/python/xen/xend/XendDevices.py
tools/python/xen/xend/XendDomainInfo.py
tools/python/xen/xend/server/netif2.py [new file with mode: 0644]
tools/python/xen/xm/create.py
tools/python/xen/xm/main.py

index 33ebdc6487e6ce2013c4363a178f33be6b35aec6..b5f9800de0d26e0752ff53b679ba5c7f954ace73 100644 (file)
@@ -11,6 +11,7 @@ XENDOMAINS_SYSCONFIG = init.d/sysconfig.xendomains
 XEN_SCRIPTS = network-bridge vif-bridge
 XEN_SCRIPTS += network-route vif-route
 XEN_SCRIPTS += network-nat vif-nat
+XEN_SCRIPTS += vif2
 XEN_SCRIPTS += block
 XEN_SCRIPTS += block-enbd block-nbd
 XEN_SCRIPTS += blktap
diff --git a/tools/hotplug/Linux/vif2 b/tools/hotplug/Linux/vif2
new file mode 100644 (file)
index 0000000..247fa67
--- /dev/null
@@ -0,0 +1,46 @@
+#!/bin/bash
+
+dir=$(dirname "$0")
+. "$dir/xen-hotplug-common.sh"
+. "$dir/xen-network-common.sh"
+
+bridge=$(xenstore_read_default "$XENBUS_PATH/bridge" "$bridge")
+if [ -z "$bridge" ]
+    then
+    nr_bridges=$(($(brctl show | cut -f 1 | grep -v "^$" | wc -l) - 1))
+    if [ "$nr_bridges" != 1 ]
+       then
+       fatal "no bridge specified, and don't know which one to use ($nr_bridges found)"
+    fi
+    bridge=$(brctl show | cut -d "
+" -f 2 | cut -f 1)
+fi
+
+command="$1"
+shift
+
+case "$command" in
+    "online")
+       if [ "$bridge" != "-" ]
+           then
+           setup_bridge_port "$vif"
+           add_to_bridge "$bridge" "$vif"
+       else
+           # Just let the normal udev rules for interfaces handle it.
+           true
+       fi
+       success
+       ;;
+
+    "add")
+       success
+       ;;
+
+    "remove")
+       ;;
+
+    *)
+       echo "Unknown command: $command"
+       echo 'Valid commands are: add, remove, online'
+       exit 1
+esac
index 3b1c1759da8d3f034dab50595affae7541af1ec6..60690b08339ad916f49d914ce6200bedeeeb8525 100644 (file)
@@ -1,8 +1,9 @@
 SUBSYSTEM=="xen-backend", KERNEL=="tap*", RUN+="/etc/xen/scripts/blktap $env{ACTION}"
 SUBSYSTEM=="xen-backend", KERNEL=="vbd*", RUN+="/etc/xen/scripts/block $env{ACTION}"
 SUBSYSTEM=="xen-backend", KERNEL=="vtpm*", RUN+="/etc/xen/scripts/vtpm $env{ACTION}"
-SUBSYSTEM=="xen-backend", KERNEL=="vif*", ACTION=="online", RUN+="$env{script} online"
-SUBSYSTEM=="xen-backend", KERNEL=="vif*", ACTION=="offline", RUN+="$env{script} offline"
+SUBSYSTEM=="xen-backend", KERNEL=="vif2-*", RUN+="/etc/xen/scripts/vif2 $env{ACTION}"
+SUBSYSTEM=="xen-backend", KERNEL=="vif-*", ACTION=="online", RUN+="$env{script} online"
+SUBSYSTEM=="xen-backend", KERNEL=="vif-*", ACTION=="offline", RUN+="$env{script} offline"
 SUBSYSTEM=="xen-backend", KERNEL=="vscsi*", RUN+="/etc/xen/scripts/vscsi $env{ACTION}"
 SUBSYSTEM=="xen-backend", ACTION=="remove", RUN+="/etc/xen/scripts/xen-hotplug-cleanup"
 KERNEL=="evtchn", NAME="xen/%k"
index b2148914321e6e10ca489b130b9753ef2cc96d6b..5cd3b65d0b27eb03680e33af9bf9ef6f342f14a7 100644 (file)
@@ -19,7 +19,7 @@
 # A collection of DevControllers 
 #
 
-from xen.xend.server import blkif, netif, tpmif, pciif, iopif, irqif, vfbif, vscsiif
+from xen.xend.server import blkif, netif, tpmif, pciif, iopif, irqif, vfbif, vscsiif, netif2
 from xen.xend.server.BlktapController import BlktapController, Blktap2Controller
 from xen.xend.server.ConsoleController import ConsoleController
 
@@ -37,6 +37,7 @@ class XendDevices:
     controllers = {
         'vbd': blkif.BlkifController,
         'vif': netif.NetifController,
+        'vif2': netif2.NetifController2,
         'vtpm': tpmif.TPMifController,
         'pci': pciif.PciController,
         'ioports': iopif.IOPortsController,
index 6848d3b3eeda056dfa3ca0b13dd53e93a0423f01..e9dfa15782bb2d47bcd36fed4aa319ca32387ffe 100644 (file)
@@ -1222,7 +1222,7 @@ class XendDomainInfo:
                         break
                 self._waitForDevice_destroy(deviceClass, devid, backend)
 
-        if rm_cfg:
+        if rm_cfg and deviceClass != "vif2":
             if deviceClass == 'vif':
                 if self.domid is not None:
                     mac = ''
diff --git a/tools/python/xen/xend/server/netif2.py b/tools/python/xen/xend/server/netif2.py
new file mode 100644 (file)
index 0000000..a098c13
--- /dev/null
@@ -0,0 +1,163 @@
+#============================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#============================================================================
+# Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
+# Copyright (C) 2005 XenSource Ltd
+# Copyright (C) 2008 Citrix Systems Inc.
+#============================================================================
+#
+# Based closely on netif.py.
+#
+
+"""Support for virtual network interfaces, version 2.
+"""
+
+import os
+import random
+import re
+import time
+
+from xen.xend import XendOptions
+from xen.xend.server.DevController import DevController
+from xen.xend.XendError import VmError
+from xen.xend.XendXSPolicyAdmin import XSPolicyAdminInstance
+from xen.xend.xenstore.xstransact import xstransact
+import xen.util.xsm.xsm as security
+
+from xen.xend.XendLogging import log
+
+xoptions = XendOptions.instance()
+
+def randomMAC():
+    """Generate a random MAC address.
+
+    Uses OUI (Organizationally Unique Identifier) 00-16-3E, allocated to
+    Xensource, Inc. The OUI list is available at
+    http://standards.ieee.org/regauth/oui/oui.txt.
+
+    The remaining 3 fields are random, with the first bit of the first
+    random field set 0.
+
+    @return: MAC address string
+    """
+    mac = [ 0x00, 0x16, 0x3e,
+            random.randint(0x00, 0x7f),
+            random.randint(0x00, 0xff),
+            random.randint(0x00, 0xff) ]
+    return ':'.join(map(lambda x: "%02x" % x, mac))
+
+class NetifController2(DevController):
+    def __init__(self, vm):
+        DevController.__init__(self, vm)
+
+    def getDeviceDetails(self, config):
+        """@see DevController.getDeviceDetails"""
+
+        devid = self.allocateDeviceID()
+
+        bridge = config.get('bridge')
+        back_mac = config.get('back_mac')
+        if not back_mac:
+            if bridge:
+                back_mac = "fe:ff:ff:ff:ff:ff"
+            else:
+                back_mac = randomMAC()
+        front_mac = config.get('front_mac') or randomMAC()
+        front_trust = config.get("trusted") or "0"
+        back_trust = config.get("back_trusted") or "1"
+        max_bypasses = config.get("max_bypasses") or "5"
+        pdev = config.get('pdev')
+        front_filter = config.get("front_filter_mac")
+        if front_filter == None:
+            if back_trust == "0":
+                front_filter = "1"
+            else:
+                front_filter = "0"
+        back_filter = config.get("filter_mac")
+        if back_filter == None:
+            if front_trust == "0":
+                back_filter = "1"
+            else:
+                back_filter = "0"
+        back = { 'mac': back_mac, 'remote-mac': front_mac,
+                 'handle': "%i" % devid, 'local-trusted': back_trust,
+                 'remote-trusted': front_trust, 'filter-mac': back_filter,
+                 'max-bypasses': max_bypasses }
+
+        front = { 'mac': front_mac, 'remote-mac': back_mac,
+                  'local-trusted': front_trust, 'remote-trusted': back_trust,
+                  'filter-mac': front_filter }
+
+        if bridge:
+            back['bridge'] = bridge
+
+        if pdev:
+            back['pdev'] = pdev
+    
+        return (devid, back, front)
+
+    def getDeviceConfiguration(self, devid, transaction = None):
+        """@see DevController.configuration"""
+
+        if transaction is None:
+            read_fn = xstransact.Read
+        else:
+            read_fn = transaction.read
+        def front_read(x):
+            return read_fn(frontpath + x)
+        def back_read(x):
+            return read_fn(backpath + x)
+        
+        result = DevController.getDeviceConfiguration(self, devid, transaction)
+
+        dev = self.convertToDeviceNumber(devid)
+        frontpath = self.frontendPath(dev) + "/"
+
+        backpath = front_read("backend") + "/"
+
+        front_mac = front_read("mac")
+        back_mac = back_read("mac")
+
+        front_trusted = back_read("remote-trusted")
+        back_trusted = back_read("local-trusted")
+        max_bypasses = back_read("max-bypasses")
+
+        bridge = back_read("bridge")
+
+        pdev = back_read("pdev")
+
+        if front_mac:
+            result["front_mac"] = front_mac
+        if back_mac:
+            result["back_mac"] = back_mac
+        if front_trusted:
+            result["front_trusted"] = front_trusted
+        if back_trusted:
+            result["back_trusted"] = back_trusted
+        if bridge:
+            result["bridge"] = bridge
+        if pdev:
+            result["pdev"] = pdev
+        if max_bypasses:
+            result["max-bypasses"] = max_bypasses
+        return result
+
+    def destroyDevice(self, devid, force):
+        dev = self.convertToDeviceNumber(devid)
+        self.writeBackend(dev, "online", "0")
+        if force:
+            self.writeBackend(dev, "shutdown-request", "force")
+        else:
+            self.writeBackend(dev, "shutdown-request", "normal")
+        self.vm._removeVm("device/%s/%d" % (self.deviceClass, dev))
index 14f8aa64258492e931ed8217e6644ea9d9bae3d1..f929011bc72dc4f6caa9366dbd46e88a30e07d0f 100644 (file)
@@ -393,6 +393,12 @@ gopts.var('vif', val="type=TYPE,mac=MAC,bridge=BRIDGE,ip=IPADDR,script=SCRIPT,"
           This option may be repeated to add more than one vif.
           Specifying vifs will increase the number of interfaces as needed.""")
 
+gopts.var('vif2', val="front_mac=MAC,back_mac=MAC,backend=DOM,pdev=PDEV,max_bypasses=N,bridge=BRIDGE,filter_mac=<0|1>,front_filter_mac=<0|1>",
+          fn=append_value, default=[],
+          use="""Add a netchannel2 network interface using given front
+          and backend MAC addresses.  Randomly generated
+          addresses will be used if either address is missing.""")
+
 gopts.var('vtpm', val="instance=INSTANCE,backend=DOM,type=TYPE",
           fn=append_value, default=[],
           use="""Add a TPM interface. On the backend side use the given
@@ -931,6 +937,8 @@ def configure_vifs(config_devs, vals):
 
     vifs = vals.vif
     vifs_n = len(vifs)
+    vifs2 = vals.vif2
+    vifs2_n = len(vifs2)
 
     if hasattr(vals, 'nics'):
         if vals.nics > 0:
@@ -957,6 +965,18 @@ def configure_vifs(config_devs, vals):
         map(f, d.keys())
         config_devs.append(['device', config_vif])
 
+    for c in vifs2:
+        d = comma_sep_kv_to_dict(c)
+        config_vif = ['vif2']
+
+        for k in d.keys():
+            if k not in ['front_mac', 'back_mac', 'backend', 'trusted',
+                         'back_trusted', 'front_filter_mac', 'filter_mac',
+                         'bridge', 'pdev', 'max_bypasses' ]:
+                err('Invalid vif2 option: ' + k)
+            config_vif.append([k, d[k]])
+        config_devs.append(['device', config_vif])
+
 
 def configure_hvm(config_image, vals):
     """Create the config for HVM devices.
index 6ffa0ed1bf3910abd1b2045c41a3b3ddd04b6f62..07f77bf29e121fc2c57dbae493d98cebfb6216cc 100644 (file)
@@ -181,6 +181,15 @@ SUBCOMMAND_HELP = {
                         'Destroy a domain\'s virtual network device.'),
     'network-list'  :  ('<Domain> [--long]',
                         'List virtual network interfaces for a domain.'),
+    'network2-attach': ('<Domain> [front_mac=<mac>] [back_mac=<mac>] '
+                        '[backend=<BackDomain>] [trusted=<0|1>] '
+                        '[back_trusted=<0|1>] [bridge=<bridge>] '
+                        '[max_bypasses=n]'
+                        'Create a new version 2 virtual network device.'),
+    'network2-detach': ('<Domain> <DevId> [-f|--force]',
+                         'Destroy a domain\'s version 2 virtual network device.'),
+    'network2-list'  : ('<Domain> [--long]',
+                        'List version 2 virtual network interfaces for a domain.'),
     'vnet-create'   :  ('<ConfigFile>','Create a vnet from ConfigFile.'),
     'vnet-delete'   :  ('<VnetId>', 'Delete a Vnet.'),
     'vnet-list'     :  ('[-l|--long]', 'List Vnets.'),
@@ -399,6 +408,9 @@ device_commands = [
     "network-attach",
     "network-detach",
     "network-list",
+    "network2-attach",
+    "network2-detach",
+    "network2-list",
     "vtpm-list",
     "pci-attach",
     "pci-detach",
@@ -2436,6 +2448,35 @@ def xm_block_configure(args):
     server.xend.domain.device_configure(dom, vbd)
 
 
+def xm_network2_attach(args):
+    xenapi_unsupported()
+    arg_check(args, 'network2-attach', 1, 4)
+    dom = args[0]
+    vif = ['vif2']
+    vif_params = ['front_mac', 'back_mac', 'backend', 'trusted',
+                  'back_trusted', "front_filter_mac", "filter_mac",
+                  'bridge', 'pdev', "max_bypasses" ]
+    for a in args[1:]:
+        vif_param = a.split("=")
+        if len(vif_param) != 2 or vif_param[1] == "" or \
+           vif_param[0] not in vif_params:
+            err("Invalid argument: %s" % a)
+            usage("network2-attach")
+        vif.append(vif_param)
+    server.xend.domain.device_create(dom, vif)
+
+def xm_network2_detach(args):
+    xenapi_unsupported()
+    arg_check(args, "network2-detch", 2, 3)
+    detach(args, "vif2")
+
+def xm_network2_list(args):
+    xenapi_unsupported()
+    (use_long, params) = arg_check_for_resource_list(args, "network2-list")
+    dom = params[0]
+    devs = server.xend.domain.getDeviceSxprs(dom, 'vif2')
+    map(PrettyPrint.prettyprint, devs)
+                
 def xm_network_attach(args):
     arg_check(args, 'network-attach', 1, 11)
 
@@ -3239,6 +3280,9 @@ commands = {
     "network-attach": xm_network_attach,
     "network-detach": xm_network_detach,
     "network-list": xm_network_list,
+    "network2-attach": xm_network2_attach,
+    "network2-detach": xm_network2_detach,
+    "network2-list": xm_network2_list,
     # network (as in XenAPI)
     "network-new": xm_network_new,
     "network-del": xm_network_del,